Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle 'Content-Length' requests #129

Merged
merged 4 commits into from
Feb 22, 2017
Merged

Conversation

legionth
Copy link
Contributor

@legionth legionth commented Feb 19, 2017

Currently Content-Length requests aren't checked for the transferred length.
The new class ensures that only the correct length will be transferred and a correct end event will be emitted.

Copy link
Member

@clue clue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Thanks for this high quality PR! 👍

May I ask you to check this wrt to its relation to #116 and #104. In particular, does this resolve #104 or do you see anything that's missing here?

src/Server.php Outdated
// Content-Length value is not an integer or not a single integer
$this->emit('error', new \Exception('The value of `Content-Length` is not valid'));
return;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but should probably also send an error response to client à la #124/#127.

src/Server.php Outdated
@@ -139,6 +139,19 @@ public function handleRequest(ConnectionInterface $conn, Request $request)
}
}

if ($request->hasHeader('Content-Length')) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you checked this wrt to chunked transfer encoding?

In particular wrt validating requests that contain both chunked transfer encoding AND a Content-Length?

src/Server.php Outdated
// stream must emit an 'end' here, because empty data won't be emitted
$stream->emit('end');
$conn->removeListener('data', array($stream, 'handleData'));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block appears a bit unclear to me, perhaps you can clarify? The $contentLength variable is defined in another scope and may not exist here (though this may not cause here due to short-circuit evaluation).

Why is this listener removed (only) here?

@clue clue added this to the v0.6.0 milestone Feb 19, 2017
@legionth legionth force-pushed the handle-body branch 2 times, most recently from df65f14 to 1fd2812 Compare February 19, 2017 20:13
@legionth
Copy link
Contributor Author

Ping @clue. I think, I handled all your remarks.

src/Server.php Outdated
if ($request->hasHeader('Content-Length')) {
// remove 'Content-Length' header accordig to: https://tools.ietf.org/html/rfc7230#section-3.3.3
$headers = $request->getHeaders();
unset($headers['Content-Length']);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm undecided on this (and won't block this), but I'd like to hear some other thoughts on this 👍

How should this be handled? Should this header be removed here?

If a message is received with both a Transfer-Encoding and a
Content-Length header field, the Transfer-Encoding overrides the
Content-Length. Such a message
might indicate an attempt to
perform request smuggling (Section 9.5) or response splitting
(Section 9.4) and ought to be handled as an error.

https://tools.ietf.org/html/rfc7230#section-3.3.3

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a bit more precised specification in the old RFC(https://www.ietf.org/rfc/rfc2616.txt chapter 4.4)

If a message is received with both a
Transfer-Encoding header field and a Content-Length header field,
the latter MUST be ignored.

This would be easier to handle and a more solid behavior.

src/Server.php Outdated
$request->getQueryParams(),
$request->getProtocolVersion(),
$headers
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, this is not particularly reliable and currently does not set the correct remoteAddress property. (see also above, as I'm not sure this is needed in the first place)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above. I found somethin in the old RFC which might eliminate this behavior.

return $this->writeError($conn, 400);
}

$stream = new LengthLimitedStream($conn, $contentLength);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if a request has neither chunked transfer encoding nor a Content-Length header (such as for simple GET requests)? Is this tested?

Should this be part of this PR? (see also #104)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

afaik every test with createGetRequest would be effected. The tests for this would be the same, to the ones that already exist.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I get what you're suggesting here and I may be missing something obvious here, but I'm specifically talking about this:

  1. If this is a request message and none of the above are true, then
    the message body length is zero (no message body is present).

https://tools.ietf.org/html/rfc7230#section-3.3.3

Is this correctly covered and tested by this PR or is this not supposed to be part of this PR? See also the PR title and #104.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edited the first comment. This only closes a part of #104

if (!$this->closed) {
$this->emit('end');
$this->close();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the stream ends before the content length has been reached? (see also chunked transfer encoding)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. If a valid Content-Length header field is present [… and] the sender closes the connection […] before the indicated number of octets are
    received, the recipient MUST consider the message to be
    incomplete and close the connection.

https://tools.ietf.org/html/rfc7230#section-3.3.3

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A error handling is missing here. Also in the ChunkedDecoder I would like to keep it out of this PR because it is currently the same state as ChunkedDecoder. I will open a separted PR for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See latest commit. An error will be emitted, so the behavior is the same like in ChunkedDecoder. I would prefer to add an error handling in an sperarted PR.

$request->on('end', $endEvent);
$request->on('close', $closeEvent);
$request->on('error', $errorEvent);
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole event will not be emitted anyway? Can be simplified a lot, see also other test cases 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to show that the correct events will be used/not used. But ok.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's exactly what I'm suggesting here :-) The whole request will not be emitted (which is not tested), as such no events can be emitted on the non-existent request object :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you commented the wrong test, that's why I was so confused. I think you wanted to mark the testNonInteger... tests here. In that case, I agree with you :)

@legionth
Copy link
Contributor Author

Ping @clue . Rebased and squashed some commits. I hope this good to review, if not just say it.

Copy link
Member

@clue clue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

Copy link
Member

@WyriHaximus WyriHaximus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@WyriHaximus WyriHaximus merged commit 34acf52 into reactphp:master Feb 22, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants